#include "precomp.h"
#include <ServerEngine/Script/ScriptSystem.h>
#include <ServerEngine/Engine.h>

#include <Squirrel/sqstdaux.h>
#include <Squirrel/sqstdblob.h>
#include <Squirrel/sqstdio.h>
#include <Squirrel/sqstdmath.h>
#include <Squirrel/sqstdstring.h>
#include <Squirrel/sqstdsystem.h>

using namespace TSE;

#ifdef SQUNICODE
	#define scfprintf fwprintf
	#define scfopen	_wfopen
	#define scvprintf vfwprintf
#else
	#define scfprintf fprintf
	#define scfopen	fopen
	#define scvprintf vfprintf
#endif

//void BindSquirrel(HSQUIRRELVM v);
//void exec(int i);

ScriptSystem::ScriptSystem(Engine &engine)
: engine(engine)
{
	vm = sq_open(1024);

	sq_setprintfunc(vm, printfunc, errorfunc);
	sq_pushroottable(vm);
	
	sqstd_register_bloblib(vm);
	sqstd_register_iolib(vm);
	sqstd_register_systemlib(vm);
	sqstd_register_mathlib(vm);
	sqstd_register_stringlib(vm);

	sqstd_seterrorhandlers(vm);

	Sqrat::DefaultVM::Set(vm);

	Sqrat::RootTable(vm).Func<bool (*)(const SQChar *, const SQChar *)>("exec", &ScriptSystem::exec);
}

ScriptSystem::~ScriptSystem()
{
	sq_close(vm);
}

void ScriptSystem::Main(int argc, char *argv[])
{
	runFile("scripts/core", "main.nut");
	runFile("scripts/game", "main.nut");
	//runString("onBaseStart();");
	//runString("onStart();");

	Sqrat::Function baseStart(Sqrat::RootTable(), "onBaseStart");
	if(baseStart.IsNull())
		CL_Console::write_line("Error: The squirrel function onBaseStart could not be found in core/main.nut!");
	else
		baseStart();

	Sqrat::Function start(Sqrat::RootTable(), "onStart");
	if(start.IsNull())
		CL_Console::write_line("Error: The squirrel function onStart could not be found in core/main.nut nor game/main.nut!");
	else
	{
		/*Sqrat::Table sqArgv;
		for(int i = 0; i < argc; i++)
			sqArgv.SetValue(cl_format("%1", i).c_str(), argv[i]);*/
		start(argc, argv[0]);
	}
}

bool ScriptSystem::runString(const CL_String &script)
{
	Sqrat::Script scr;
	try
	{
		scr.CompileString(_SC(script.c_str()));
	}
	catch(Sqrat::Exception &e)
	{
		CL_Console::write_line(cl_format("string script compile failed: %1", e.Message().c_str()));
		return false;
	}

	try 
	{
		scr.Run();
	} 
	catch(Sqrat::Exception &e) 
	{
		CL_Console::write_line(cl_format("string script run failed: %1", e.Message().c_str()));
		return false;
	}
	return true;
}
bool ScriptSystem::runFile(const CL_String &rel_path, const CL_String &filename)
{
	Sqrat::Script scr;
	try
	{
		CL_String abs_path = cl_format("%1%2/%3", engine.getRootPath(), rel_path, filename);
		scr.CompileFile(_SC(abs_path.c_str()));
	}
	catch(Sqrat::Exception &e)
	{
		CL_Console::write_line(cl_format("file script %1 compile failed: %2", filename, e.Message().c_str()));
		return false;
	}

	try 
	{
		scr.Run();
	} 
	catch(Sqrat::Exception &e) 
	{
		CL_Console::write_line(cl_format("file script %1 run failed: %2", filename, e.Message().c_str()));
		return false;
	}
	return true;
}

void ScriptSystem::printfunc(HSQUIRRELVM v,const SQChar *s,...)
{
	va_list vl;
	va_start(vl, s);
	scvprintf(stdout, s, vl);
	CL_Console::write_line("");
	va_end(vl);
}

void ScriptSystem::errorfunc(HSQUIRRELVM v,const SQChar *s,...)
{
	va_list vl;
	va_start(vl, s);
	scvprintf(stderr, s, vl);
	CL_Console::write_line("");
	va_end(vl);
}

bool ScriptSystem::exec(const SQChar *rel_path, const SQChar *filename)
{
	CL_String rootPath = CL_System::get_exe_path();
	Sqrat::Script scr;
	try
	{
		CL_String abs_path = cl_format("%1scripts/%2/%3", rootPath, rel_path, filename);
		scr.CompileFile(_SC(abs_path.c_str()));
	}
	catch(Sqrat::Exception &e)
	{
		CL_Console::write_line(cl_format("file script %1/%2 compile failed: %3", rel_path, filename, e.Message().c_str()));
		return false;
	}

	try 
	{
		scr.Run();
	} 
	catch(Sqrat::Exception &e) 
	{
		CL_Console::write_line(cl_format("file script %1/%2 run failed: %3", rel_path, filename, e.Message().c_str()));
		return false;
	}
	return true;
}
